package seismosurfer.gui.panel;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import seismosurfer.data.QuakeClientData;
import seismosurfer.data.QuakeMaxMinData;
import seismosurfer.data.constants.ParameterNames;
import seismosurfer.data.constants.QueryNames;
import seismosurfer.gui.DateSelector;
import seismosurfer.gui.GUIConstants;
import seismosurfer.gui.menu.QueryMenu;
import seismosurfer.layer.QuakeLayer;

import com.bbn.openmap.MapBean;
import com.bbn.openmap.gui.OMComponentPanel;

/**
 * The "Range Query" panel.
 *
 */
public class RangePanel extends OMComponentPanel implements
        PropertyChangeListener, ParameterNames, QueryNames, Serializable,
        GUIConstants {
    
    private static final long serialVersionUID = 2814179315268583814L;

    private MapBean map = null;

    private QuakeLayer ql = null;

    private double initlatmin;

    private double initlatmax;

    private double initlongmin;

    private double initlongmax;

    // SpinButtons for selecting range of values of the available attributes.
    protected JSpinner MagMin, MagMax, DMin, DMax, LatMin, LatMax, LongMin,
            LongMax;

    protected SpinnerNumberModel LatMinSpinModel, LatMaxSpinModel,
            LongMinSpinModel, LongMaxSpinModel;

    protected SpinnerNumberModel MagMinSpinModel, MagMaxSpinModel,
            DMinSpinModel, DMaxSpinModel;

    // Date selectors consisting of three combo boxes each: year, month, day.
    protected DateSelector TimeMin, TimeMax;

    public RangePanel(ActionListener buttonsListener) {
        super();
        createPanel(buttonsListener);
    }

    protected void createPanel(ActionListener buttonsListener) {

        try {

            // These are useful for getting min, max values from the DB
            // for the SpinButtons and the Date Selectors.

            double min, max;

            // A Panel to hold the controls
            JPanel FilterPane = new JPanel();
            GridBagLayout FilterPaneLayout = new GridBagLayout();
            FilterPane.setLayout(FilterPaneLayout);
            GridBagConstraints c = new GridBagConstraints();

            JLabel MagLabel = new JLabel("Magnitude");
            JLabel FilterLabel = new JLabel("Filters");
            JLabel FromLabel = new JLabel("From");
            JLabel ToLabel = new JLabel("To");

            min = QuakeMaxMinData.getDBMinMagnitude();
            max = QuakeMaxMinData.getDBMaxMagnitude();

            MagMinSpinModel = new SpinnerNumberModel(min + 0.1, min, max, 0.1); // (initial
            // value,
            // min,
            // max,
            // step)
            MagMin = new JSpinner(MagMinSpinModel);

            MagMaxSpinModel = new SpinnerNumberModel(max, min, max, 0.1);
            MagMax = new JSpinner(MagMaxSpinModel);

            c.gridx = 0;
            c.gridy = 0;
            c.anchor = GridBagConstraints.WEST;
            FilterPaneLayout.setConstraints(FilterLabel, c);
            FilterPane.add(FilterLabel);
            c.gridx = 1;
            c.gridy = 0;
            FilterPaneLayout.setConstraints(FromLabel, c);
            FilterPane.add(FromLabel);
            c.gridx = 2;
            c.gridy = 0;
            FilterPaneLayout.setConstraints(ToLabel, c);
            FilterPane.add(ToLabel);

            c.gridx = 0;
            c.gridy = 1;
            FilterPaneLayout.setConstraints(MagLabel, c);
            FilterPane.add(MagLabel);
            c.gridx = 1;
            c.gridy = 1;
            c.fill = GridBagConstraints.BOTH;
            FilterPaneLayout.setConstraints(MagMin, c);
            FilterPane.add(MagMin);
            c.gridx = 2;
            c.gridy = 1;
            c.fill = GridBagConstraints.BOTH;
            FilterPaneLayout.setConstraints(MagMax, c);
            FilterPane.add(MagMax);

            JLabel DLabel = new JLabel("Depth");

            min = QuakeMaxMinData.getDBMinDepth();
            max = QuakeMaxMinData.getDBMaxDepth();

            DMinSpinModel = new SpinnerNumberModel(min, min, max, 1.0);
            DMin = new JSpinner(DMinSpinModel);

            DMaxSpinModel = new SpinnerNumberModel(max, min, max, 1.0);
            DMax = new JSpinner(DMaxSpinModel);

            c.gridx = 0;
            c.gridy = 2;
            c.fill = GridBagConstraints.NONE;
            FilterPaneLayout.setConstraints(DLabel, c);
            FilterPane.add(DLabel);
            c.gridx = 1;
            c.gridy = 2;
            c.fill = GridBagConstraints.BOTH;
            FilterPaneLayout.setConstraints(DMin, c);
            FilterPane.add(DMin);
            c.gridx = 2;
            c.gridy = 2;
            c.fill = GridBagConstraints.BOTH;
            FilterPaneLayout.setConstraints(DMax, c);
            FilterPane.add(DMax);

            JLabel LatLabel = new JLabel("Latitude");
            LatMinSpinModel = new SpinnerNumberModel(initlatmin, -90, 90, 0.1);
            LatMaxSpinModel = new SpinnerNumberModel(initlatmax, -90, 90, 0.1);
            LatMin = new JSpinner(LatMinSpinModel);
            LatMax = new JSpinner(LatMaxSpinModel);
            c.gridx = 0;
            c.gridy = 3;
            c.fill = GridBagConstraints.NONE;
            FilterPaneLayout.setConstraints(LatLabel, c);
            FilterPane.add(LatLabel);
            c.gridx = 1;
            c.gridy = 3;
            c.fill = GridBagConstraints.BOTH;
            FilterPaneLayout.setConstraints(LatMin, c);
            FilterPane.add(LatMin);
            c.gridx = 2;
            c.gridy = 3;
            c.fill = GridBagConstraints.BOTH;
            FilterPaneLayout.setConstraints(LatMax, c);
            FilterPane.add(LatMax);

            JLabel LongLabel = new JLabel("Longitude");
            LongMinSpinModel = new SpinnerNumberModel(initlongmin, -180, 180,
                    0.1);
            LongMaxSpinModel = new SpinnerNumberModel(initlongmax, -180, 180,
                    0.1);
            LongMin = new JSpinner(LongMinSpinModel);
            LongMax = new JSpinner(LongMaxSpinModel);
            c.gridx = 0;
            c.gridy = 4;
            c.fill = GridBagConstraints.NONE;
            FilterPaneLayout.setConstraints(LongLabel, c);
            FilterPane.add(LongLabel);
            c.gridx = 1;
            c.gridy = 4;
            c.fill = GridBagConstraints.BOTH;
            FilterPaneLayout.setConstraints(LongMin, c);
            FilterPane.add(LongMin);
            c.gridx = 2;
            c.gridy = 4;
            c.fill = GridBagConstraints.BOTH;
            FilterPaneLayout.setConstraints(LongMax, c);
            FilterPane.add(LongMax);

            JLabel TimeLabel = new JLabel("Time");

            long tmin = QuakeMaxMinData.getDBMinTime();
            long tmax = QuakeMaxMinData.getDBMaxTime();

            TimeMin = new DateSelector(tmin, tmin, tmax);
            TimeMax = new DateSelector(tmax, tmin, tmax);

            c.gridx = 0;
            c.gridy = 5;
            c.fill = GridBagConstraints.NONE;
            FilterPaneLayout.setConstraints(TimeLabel, c);
            FilterPane.add(TimeLabel);
            c.gridx = 1;
            c.gridy = 5;
            FilterPaneLayout.setConstraints(TimeMin, c);
            FilterPane.add(TimeMin);
            c.gridx = 2;
            c.gridy = 5;
            FilterPaneLayout.setConstraints(TimeMax, c);
            FilterPane.add(TimeMax);

            // bottomPanel consists of 2 buttons: OK and Cancel.
            JPanel bottomPanel = new JPanel();
            bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS));
            JButton b1 = new JButton("OK");
            // b1.addActionListener(this);
            b1.addActionListener(buttonsListener);
            b1.setActionCommand(OK);
            bottomPanel.add(b1);

            JButton b2 = new JButton("Cancel");
            b2.addActionListener(buttonsListener);
            b2.setActionCommand(CANCEL);
            bottomPanel.add(b2);

            // setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
            // Container contentPane = getContentPane();
            GridBagLayout contentPaneLayout = new GridBagLayout();
            GridBagConstraints ccP = new GridBagConstraints();
            setLayout(contentPaneLayout);
            ccP.gridx = 0;
            ccP.gridy = 0;
            contentPaneLayout.setConstraints(FilterPane, ccP);
            add(FilterPane);
            ccP.gridx = 0;
            ccP.gridy = 1;
            contentPaneLayout.setConstraints(bottomPanel, ccP);
            add(bottomPanel);
            setLayout(contentPaneLayout);

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }

    }

    public void sendQueryParameters() {
        try {

            Map parameters = new HashMap();

            parameters.put(TIME_MIN, new Long(TimeMin.getValue()));
            parameters.put(TIME_MAX, new Long(TimeMax.getValue()));

            parameters.put(DEPTH_MIN, (Double) DMin.getValue());
            parameters.put(DEPTH_MAX, (Double) DMax.getValue());

            parameters.put(MAG_MIN, (Double) MagMin.getValue());
            parameters.put(MAG_MAX, (Double) MagMax.getValue());

            parameters.put(LONG_MIN, (Double) LongMin.getValue());
            parameters.put(LAT_MIN, (Double) LatMin.getValue());

            parameters.put(LONG_MAX, (Double) LongMax.getValue());
            parameters.put(LAT_MAX, (Double) LatMax.getValue());

            parameters.put(SOURCE, getSource());

            if (ql != null) {
                ql.loadQuakeClientData(QueryNames.RANGE, parameters);
            } else {
                System.out.println("NULL Layer!!!");
            }

        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

    }

    public void updateDialogValues() {
        setCoordinates();
        setValues();
    }

    protected void setValues() {

        double min = 0, max = 0, tempinitval = 0;
        int count = 0;

        count = QuakeClientData.getRowCount();

        min = QuakeMaxMinData.getDBMinMagnitude();
        max = QuakeMaxMinData.getDBMaxMagnitude();

        tempinitval = (count > 0) ? QuakeClientData.getMinMagnitude()
                : (min + 0.1);
        MagMinSpinModel.setValue(new Double(tempinitval));

        tempinitval = (count > 0) ? QuakeClientData.getMaxMagnitude() : max;
        MagMaxSpinModel.setValue(new Double(tempinitval));

        min = QuakeMaxMinData.getDBMinDepth();
        max = QuakeMaxMinData.getDBMaxDepth();

        tempinitval = (count > 0) ? QuakeClientData.getMinDepth() : min;
        DMinSpinModel.setValue(new Double(tempinitval));

        tempinitval = (count > 0) ? QuakeClientData.getMaxDepth() : max;
        DMaxSpinModel.setValue(new Double(tempinitval));

        long tmin = QuakeMaxMinData.getDBMinTime();
        long tmax = QuakeMaxMinData.getDBMaxTime();

        long temptinitval = (count > 0) ? QuakeClientData.getMinTime() : tmin;

        TimeMin.setSelectedDate(temptinitval);

        temptinitval = (count > 0) ? QuakeClientData.getMaxTime() : tmax;

        TimeMax.setSelectedDate(temptinitval);

    }

    protected void setCoordinates() {

        if (map != null) {

            initlatmin = ((map.getProjection()).getLowerRight()).getLatitude();
            initlatmax = ((map.getProjection()).getUpperLeft()).getLatitude();
            initlongmin = ((map.getProjection()).getUpperLeft()).getLongitude();
            initlongmax = ((map.getProjection()).getLowerRight())
                    .getLongitude();

            LatMinSpinModel.setValue(new Double(initlatmin));
            LatMaxSpinModel.setValue(new Double(initlatmax));
            LongMinSpinModel.setValue(new Double(initlongmin));
            LongMaxSpinModel.setValue(new Double(initlongmax));
        }
    }

    public void findAndInit(Object someObj) {
        if (someObj instanceof QuakeLayer) {
            ql = (QuakeLayer) someObj;
        }

        if (someObj instanceof MapBean) {
            map = (MapBean) someObj;
            setCoordinates();
        }
    }

    public void findAndUndo(Object someObj) {
        if (someObj instanceof MapBean && map == someObj) {
            map = null;
        }
    }

    public void propertyChange(PropertyChangeEvent e) {
        if (e.getPropertyName().equalsIgnoreCase(QueryMenu.SourceProperty)) {
            setSource((String) e.getNewValue());
        }
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    private String source;
}
